package handler

import (
	"encoding/json"
	"fmt"
	"go-admin/app/admin/models"
	"go-admin/common"
	"net/http"

	"go-admin/common/global"
	"io/ioutil"

	"github.com/gin-gonic/gin"
	"github.com/go-admin-team/go-admin-core/sdk"
	"github.com/go-admin-team/go-admin-core/sdk/api"
	"github.com/go-admin-team/go-admin-core/sdk/config"
	"github.com/go-admin-team/go-admin-core/sdk/pkg"
	"github.com/go-admin-team/go-admin-core/sdk/pkg/captcha"
	jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
	"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
	"github.com/go-admin-team/go-admin-core/sdk/pkg/response"
	"github.com/mssola/user_agent"
)

func PayloadFunc(data interface{}) jwt.MapClaims {
	if v, ok := data.(map[string]interface{}); ok {
		u, _ := v["user"].(SysUser)
		r, _ := v["role"].(SysRole)
		return jwt.MapClaims{
			jwt.IdentityKey:  u.UserId,
			jwt.RoleIdKey:    r.RoleId,
			jwt.RoleKey:      r.RoleKey,
			jwt.NiceKey:      u.Username,
			jwt.DataScopeKey: r.DataScope,
			jwt.RoleNameKey:  r.RoleName,
		}
	}
	return jwt.MapClaims{}
}

func IdentityHandler(c *gin.Context) interface{} {
	claims := jwt.ExtractClaims(c)
	return map[string]interface{}{
		"IdentityKey": claims["identity"],
		"UserName":    claims["nice"],
		"RoleKey":     claims["rolekey"],
		"UserId":      claims["identity"],
		"RoleIds":     claims["roleid"],
		"DataScope":   claims["datascope"],
	}
}

// getWechatOpenid 通过code获取微信openid
func getWechatOpenid(code string) (string, error) {
	// 从配置中获取appid和secret
	appid := "wx8447eddcbfb8d6e5"
	secret := "1dc9ebef5ab9c04f288c4fea69375463"

	// 检查配置是否存在
	if appid == "" || secret == "" {
		return "", fmt.Errorf("微信配置不存在")
	}

	// 微信code2Session接口
	uRL := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appid, secret, code)

	// 发送HTTP GET请求
	resp, err := http.Get(uRL)
	if err != nil {
		return "", fmt.Errorf("请求微信API失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取响应失败: %v", err)
	}

	// 解析JSON
	var result map[string]interface{}
	if err := json.Unmarshal(body, &result); err != nil {
		return "", fmt.Errorf("解析响应失败: %v", err)
	}

	// 检查是否有错误
	if errcode, ok := result["errcode"].(float64); ok && errcode != 0 {
		errmsg := result["errmsg"].(string)
		return "", fmt.Errorf("微信API返回错误: %d, %s", int(errcode), errmsg)
	}

	// 获取openid
	openid, ok := result["openid"].(string)
	if !ok || openid == "" {
		return "", fmt.Errorf("获取openid失败")
	}

	return openid, nil
}

// Authenticator 获取token
// @Summary 登陆
// @Description 获取token
// @Description LoginHandler can be used by clients to get a jwt token.
// @Description Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}.
// @Description Reply will be of the form {"token": "TOKEN"}.
// @Description dev mode：It should be noted that all fields cannot be empty, and a value of 0 can be passed in addition to the account password
// @Description 注意：开发模式：需要注意全部字段不能为空，账号密码外可以传入0值
// @Tags 登陆
// @Accept  application/json
// @Product application/json
// @Param account body Login  true "account"
// @Success 200 {string} string "{"code": 200, "expire": "2019-08-07T12:45:48+08:00", "token": ".eyJleHAiOjE1NjUxNTMxNDgsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTU2NTE0OTU0OH0.-zvzHvbg0A" }"
// @Router /api/v1/login [post]
func Authenticator(c *gin.Context) (interface{}, error) {
	log := api.GetRequestLogger(c)
	db, err := pkg.GetOrm(c)
	if err != nil {
		log.Errorf("get db error, %s", err.Error())
		response.Error(c, 500, err, "数据库连接获取失败")
		return nil, jwt.ErrFailedAuthentication
	}

	var loginVals Login
	var status = "2"
	var msg = "登录成功"
	var username = ""
	defer func() {
		LoginLogToDB(c, status, msg, username)
	}()

	if err = c.ShouldBind(&loginVals); err != nil {
		username = loginVals.Username
		msg = "数据解析失败"
		status = "1"

		return nil, jwt.ErrMissingLoginValues
	}
	// 支持微信登录（通过code获取openid）
	if loginVals.Code != "" {
		// 调用微信API获取openid
		wechatOpenid, err := getWechatOpenid(loginVals.Code)
		if err != nil {
			msg = "获取微信openid失败"
			status = "1"
			log.Warnf("Get wechat openid failed: %s", err.Error())
			return nil, jwt.ErrFailedAuthentication
		}

		// 测试使用固定openid
		// wechatOpenid := "test_openid_" + loginVals.Code

		// 检查用户是否存在
		sysUser := models.SysUser{}
		result := db.Where("wechat_openid = ? and status = '2'", wechatOpenid).First(&sysUser)

		// 如果用户不存在，创建新用户
		if result.Error != nil {
			// 创建新用户
			sysUser = models.SysUser{
				Username:     "wx_user_" + wechatOpenid[:8],
				Password:     "e10adc3949ba59abbe56e057f20f883e", // 默认密码123456的MD5哈希
				WechatOpenid: wechatOpenid,
				Status:       "2", // 启用
				DeptId:       1,
				PostId:       1,
			}
			sysUser.CreateBy = 1

			// 安全地获取用户信息
			if nickName, ok := loginVals.UserInfo["nickName"].(string); ok {
				sysUser.NickName = nickName
			}
			if avatarUrl, ok := loginVals.UserInfo["avatarUrl"].(string); ok {
				sysUser.Avatar = avatarUrl
			}
			if err := db.Create(&sysUser).Error; err != nil {
				msg = "创建用户失败"
				status = "1"
				log.Warnf("Create user failed: %s", err.Error())
				return nil, jwt.ErrFailedAuthentication
			}
		}

		// 获取用户角色
		role := models.SysRole{}
		db.Where("role_id = ?", sysUser.RoleId).First(&role)

		// 如果用户没有角色，分配默认角色
		if role.RoleId == 0 {
			db.Where("role_key = ?", "admin").First(&role)
			sysUser.RoleId = role.RoleId
			db.Save(&sysUser)
		}

		username = sysUser.NickName

		loginVals.WechatOpenid = wechatOpenid
		sysUser1, role1, e := loginVals.GetWechatUser(db)
		if e == nil {

			return map[string]interface{}{"user": sysUser1, "role": role1}, nil
		} else {
			msg = "登录失败"
			status = "1"
			log.Warnf("%s login failed!", username)
		}
		// return map[string]interface{}{"user": sysUser, "role": role}, nil
	} else {
		// 用户名密码登录需要验证账号密码
		if loginVals.Username == "" || loginVals.Password == "" {
			username = loginVals.Username
			msg = "用户名和密码不能为空"
			status = "1"
			return nil, jwt.ErrMissingLoginValues
		}
		// 非开发模式需要验证验证码
		if config.ApplicationConfig.Mode != "dev" {
			if loginVals.UUID == "" || loginVals.Code == "" {
				username = loginVals.Username
				msg = "验证码和UUID不能为空"
				status = "1"
				return nil, jwt.ErrMissingLoginValues
			}
			if !captcha.Verify(loginVals.UUID, loginVals.Code, true) {
				username = loginVals.Username
				msg = "验证码错误"
				status = "1"
				return nil, jwt.ErrInvalidVerificationode
			}
		}
	}
	sysUser, role, e := loginVals.GetUser(db)
	if e == nil {
		username = loginVals.Username

		return map[string]interface{}{"user": sysUser, "role": role}, nil
	} else {
		msg = "登录失败"
		status = "1"
		log.Warnf("%s login failed!", loginVals.Username)
	}
	return nil, jwt.ErrFailedAuthentication
}

// LoginLogToDB Write log to database
func LoginLogToDB(c *gin.Context, status string, msg string, username string) {
	if !config.LoggerConfig.EnabledDB {
		return
	}
	log := api.GetRequestLogger(c)
	l := make(map[string]interface{})

	ua := user_agent.New(c.Request.UserAgent())
	l["ipaddr"] = common.GetClientIP(c)
	l["loginLocation"] = "" // pkg.GetLocation(common.GetClientIP(c),gaConfig.ExtConfig.AMap.Key)
	l["loginTime"] = pkg.GetCurrentTime()
	l["status"] = status
	l["remark"] = c.Request.UserAgent()
	browserName, browserVersion := ua.Browser()
	l["browser"] = browserName + " " + browserVersion
	l["os"] = ua.OS()
	l["platform"] = ua.Platform()
	l["username"] = username
	l["msg"] = msg

	q := sdk.Runtime.GetMemoryQueue(c.Request.Host)
	message, err := sdk.Runtime.GetStreamMessage("", global.LoginLog, l)
	if err != nil {
		log.Errorf("GetStreamMessage error, %s", err.Error())
		//日志报错错误，不中断请求
	} else {
		err = q.Append(message)
		if err != nil {
			log.Errorf("Append message error, %s", err.Error())
		}
	}
}

// LogOut
// @Summary 退出登录
// @Description 获取token
// LoginHandler can be used by clients to get a jwt token.
// Reply will be of the form {"token": "TOKEN"}.
// @Accept  application/json
// @Product application/json
// @Success 200 {string} string "{"code": 200, "msg": "成功退出系统" }"
// @Router /logout [post]
// @Security Bearer
func LogOut(c *gin.Context) {
	LoginLogToDB(c, "2", "退出成功", user.GetUserName(c))
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "退出成功",
	})

}

func Authorizator(data interface{}, c *gin.Context) bool {

	if v, ok := data.(map[string]interface{}); ok {
		u, _ := v["user"].(models.SysUser)
		r, _ := v["role"].(models.SysRole)
		c.Set("role", r.RoleName)
		c.Set("roleIds", r.RoleId)
		c.Set("userId", u.UserId)
		c.Set("userName", u.Username)
		c.Set("dataScope", r.DataScope)
		return true
	}
	return false
}

func Unauthorized(c *gin.Context, code int, message string) {
	c.JSON(http.StatusOK, gin.H{
		"code": code,
		"msg":  message,
	})
}
